package com.example.test.component;
import com.example.test.entity.Message;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@Component
@Service
@ServerEndpoint(value = "/websocket/{username}")
public class WebSocketServer{
    private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
    private static final ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    private static final Map<String, List<Message>> offlineMessages = new ConcurrentHashMap<>();
    private Session session;
    private String username = "";
    private ObjectMapper objectMapper = new ObjectMapper()
            .registerModule(new JavaTimeModule())
            .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username) {
        this.session = session;
        this.username = username;
        webSocketMap.put(username, this);
        // 当用户上线时，发送离线消息
        List<Message> messages = offlineMessages.remove(username);
        if (messages != null) {
            messages.forEach(message -> {
                try {
                    this.sendMessage(objectMapper.writeValueAsString(message));
                } catch (IOException e) {
                    logger.error("发送离线消息时发生错误", e);
                }
            });
            logger.info("用户:" + username + "上线，离线消息已发送");
        }
        logger.info("用户:" + username + "连接:当前在线人数为:" + webSocketMap.size());
    }

    @OnClose
    public void onClose() {
        webSocketMap.remove(username);
        logger.info("用户" + username + "退出:当前在线人数为:" + webSocketMap.size());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            // 尝试解析为标准消息格式
            Message msg = objectMapper.readValue(message, Message.class);

            // 检查是否为'reconnect'动作
            if ("reconnect".equals(msg.action)) {
                String username = getUsernameFromSession(session);
                if (username != null) {
                    // 发送离线消息
                    List<Message> messages = offlineMessages.remove(username);
                    if (messages != null) {
                        messages.forEach(msgToSend -> {
                            try {
                                this.sendMessage(objectMapper.writeValueAsString(msgToSend));
                            } catch (IOException e) {
                                logger.error("发送离线消息时发生错误", e);
                            }
                        });
                        logger.info("用户:" + username + "上线，离线消息已发送");
                    }
                }
            } else {
                // 消息目标检查
                if (msg.to != null && !msg.to.isEmpty()) {
                    sendToUser(msg.to, msg);
                } else {
                    logger.error("消息目标未指定或无效");
                }
            }
        } catch (JsonMappingException e) {
            // 这里捕获JsonMappingException是因为我们尝试解析JSON数据为Message类
            // 如果JSON结构不符合Message类的预期，将抛出此异常
            logger.error("消息解析失败：" + e.getMessage());
        } catch (IOException e) {
            logger.error("IO异常：" + e.getMessage());
        }
    }

    // 假设这是一个辅助方法，用于从Session中获取用户名
    private String getUsernameFromSession(Session session) {
        return ""; // 返回实际的用户名
    }

    private void sendToUser(String activeUsername, Message message) {
        if (StringUtils.isNotBlank(activeUsername)) {
            WebSocketServer targetWebSocket = webSocketMap.get(activeUsername);
            if (targetWebSocket != null) {
                try {
                    String serializedMessage = objectMapper.writeValueAsString(message);
                    targetWebSocket.sendMessage(serializedMessage);
                    logger.info("用户:" + username + "消息已发送");
                    // 标记消息为已传递或更新其状态
                } catch (IOException e) {
                    logger.error("发送消息失败", e);
                }
            } else {
                // 接收者离线，存储消息
                List<Message> messages = offlineMessages.computeIfAbsent(activeUsername, k -> new CopyOnWriteArrayList<>());
                messages.add(message);
                logger.info("用户 " + activeUsername + " 离线，消息已存储。");
            }
        } else {
            logger.error("目标用户名无效: " + activeUsername);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        logger.error("用户" + username + "错误:原因:" + error.getMessage());
        error.printStackTrace();
    }

    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
}